Introduction

In this reading, you will recap some key concepts explained previously in this course, related to sorting and filtering data in iOS. In this recap, you will also be reminded how you can use @FetchRequest in conjunction with sort descriptors and predicates to create all kinds of sorting and filtering respectively.

First, let’s start with Core Data.

Core Data

As explained previously in this course, Core Data works by defining entities that storereal data and relationships between entities that can relate one to the other.

To obtain more information about working with Core Data, review the following learning materials from the Working with data in iOS course:

In the reading Using classes with Core Data in depth in Module 3, Lesson 1, you can also find out how to create your own NSManagedObject classes to bring more power to your fetching and save time typing.

Sorting data

In previous courses, you learned that you need to use a property wrapper called FetchRequest to retrieve data in real-time from a Core Data entity.

You also learned that this wrapper creates a link between user interface elements and the Core Entities, in a way that changes to the database will show on-screen, and inputs from interface elements will be written in the database.

For more detail on this topic, please visit the following lesson items from the Working with Data in iOS course , specifically:

Filtering data

Imagine a page in the Little Lemon app shows a list of dishes and you want to provide the user with a mechanism that can be used to search for a particular dish by name. Filtering the list is the way you achieve that.

Consider the following code responsible for retrieving data from Core Data that gathers a list of dishes from the Little Lemon restaurant. The code retrieves data in ascending, alphabetical order.

@FetchRequest(  
    sortDescriptors: [NSSortDescriptor(keyPath: \Dish.name,   
    ascending: true)],  
    animation: .default)  
private var dishes: FetchedResults<Dish> 

To filter Core Data entries, you must slightly change the FetchRequest command. Take note that the property wrapper now contains a predicate entry that is assigned, initially, to nspredicate that is always true. This predicate tells Swift that you do not want any filtering.

@FetchRequest(   
        sortDescriptors: [NSSortDescriptor(keyPath: \Dish.name,   
                                      ascending: true)],   
        predicate:NSPredicate(value: true),   
        animation: .default)   
        var dishes: FetchedResults<Dish>   

To filter Core Data, you must use a syntax that tells Swift to just show dishes that contain the word “cheese”.

The "c" letter inside the square bracket tells Swift to do case-insensitive filtering, and the "d" letter inside the square bracket tells the filtering to be diacritic insensitive. This means that accented foreign characters will be treated as regular ones and included in the results.

@FetchRequest(   
        sortDescriptors: [NSSortDescriptor(keyPath: \Dish.name,    
                                           ascending: true)],   
        predicate: NSPredicate(format: "name CONTAINS[cd] %@", "cheese"),   
        animation: .default)   
        var dishes: FetchedResults<Dish>   

@FetchRequest syntax

The basic syntax of the @FetchRequest API is as follows:

    @FetchRequest( 
        sortDescriptors: [], 
        predicate: NSPredicate(value: true), 
        animation: .default) 
    private var dishes: FetchedResults<Dish> 

This syntax, as explained previously in this course, will fetch dishes from the Dish entity. In the way the code is written right now, there is no filtering because you are passing a predicate that is always true and no sorting because you are passing an empty array of sort descriptors, so the dishes will be retrieved from the database in no specific order.

In terms of sorting, you can pass an array of sort descriptors and have a very complex sorting, where sorting happens first by name in alphabetical order and then by size in reverse alphabetical order. This is shown by the following code:

[NSSortDescriptor(key: "name", 
            ascending: true, 
             selector:  
                #selector(NSString.localizedCaseInsensitiveCompare)), 
 NSSortDescriptor(key: "size", 
            ascending: false, 
             selector:  
                #selector(NSString.localizedCaseInsensitiveCompare)] 

To filter a database, you use NSPredicates . Again, you can combine them to create complex sorting, as defined by the following code, where filtering just shows entries, whose price is below 100 and customerName contains the string "John Doe".

        let predicate1 = NSPredicate(format: "productPrice < %@)", 100) 
        let predicate2 = NSPredicate(format: "customerName CONTAINS[cd] %@",  
                                     "John Doe") 

        let compoundPredicate = NSCompoundPredicate(type: .and,  
                                     subpredicates: [predicate1, predicate2]) 

For more information about this topic, please review the following readings from the Working with Data in iOS course:

Conclusion

In this reading, you’ve recapped the key aspects of fetching, filtering, and sorting data in Core Data. In your own app, you can use this knowledge to create a list of items that can be filtered and sorted as wished, giving extreme power to the user.